package org.example.musicproject.util;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * @Author：洛洛
 * @User:Admin
 * @Package：com.luo.utils
 * @Project：BookDemo
 * @Filename: null.java
 * @name：DButils
 * @Date：2024/10/16 16:14
 * @Filename：DButils 连接池和数据库操作
 */

public class DButil {
    private static String driver;
    private static String url;
    private static String username;
    private static String password;

    public static Connection conn;
    public static ResultSet rs;

    static {
        Properties pro = new Properties();
        InputStream in = DButil.class.getResourceAsStream("/jdbc.properties");

        try {
            pro.load(in);

        driver = pro.getProperty("driver");
        url = pro.getProperty("url");
        username = pro.getProperty("user");
        password = pro.getProperty("password");

            Class.forName(driver);
        } catch (IOException | ClassNotFoundException e) {
            throw new RuntimeException("数据库获取数据失败或驱动失败" + e.getMessage());
        }
    }

    /**
     * 用于执行sql中select语句查询所有,可以加条件查询
     *
     * @param sql        预定义sql语句
     * @param clazz      实体类的Class对象
     * @param parameters 根据条件查询的条件可变参数
     * @param <T>        实体类
     * @return 返回一个结果集
     */
    public static <T> List<T> list(String sql, Class<T> clazz, Object... parameters) {
        List<T> list = new ArrayList<>();
        try (Connection con = getConn()) {
            try (PreparedStatement stmt = con.prepareStatement(sql)) {
                /*动态替换参数*/
                int index = 1;
                for (Object param : parameters) {
                    stmt.setObject(index++, param);
                }

                ResultSet rs = stmt.executeQuery();
                while (rs.next()) {
                    T t = getObject(clazz, rs);
                    list.add(t);
                }
            } catch (InstantiationException e) {
                throw new RuntimeException("数据表中的数据映射到实现类对象失败:" + e.getMessage());
            }
        } catch (SQLException | IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException("数据表中的数据映射到实现类对象失败:" + e.getMessage());
        }
        return list;
    }

    /**
     * 按条件查询一个唯一实体对象
     *
     * @param sql        预定义sql语句
     * @param clazz      实体类的Class对象
     * @param parameters 根据条件查询的条件可变参数
     * @param <T>        实体类
     * @return 返回一个唯一实体对象
     */
    public static <T> T one(String sql, Class<T> clazz, Object... parameters) {
        T t = null;
        try (Connection con = getConn()) {
            try (PreparedStatement stmt = con.prepareStatement(sql)) {
                /*动态替换参数*/
                int index = 1;
                for (Object param : parameters) {
                    stmt.setObject(index++, param);
                }
                ResultSet rs = stmt.executeQuery();
                if (rs.next()) {
                    t = getObject(clazz, rs);
                }
            } catch (InstantiationException e) {
                throw new RuntimeException("数据表中的数据映射到实现类对象失败:" + e.getMessage());
            }
        } catch (SQLException | IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException("数据表中的数据映射到实现类对象失败:" + e.getMessage());
        }
        return t;
    }

    /**
     * 更新数据表的操作，支持动态可变参数
     *
     * @param sql        数据库中的update,insert,delete操作的SQL语句
     * @param parameters 用于预处理sql语句的可变参数
     * @return 返回受影响的行数
     */
    public static int update(String sql, Object... parameters) {
        return update(getConn(), sql, parameters);
    }
    /**
     * 更新数据表的操作，支持动态可变参数
     *
     * @param sql        数据库中的update,insert,delete操作的SQL语句
     * @param parameters 用于预处理sql语句的可变参数
     * @return 返回受影响的行数
     */
    public static int update(Connection conn, String sql, Object... parameters) {
        int row = 0;
        try (PreparedStatement stmt = conn.prepareStatement(sql)) {
            /*动态替换参数*/
            int index = 1;
            for (Object param : parameters) {
                stmt.setObject(index++, param);
            }
            row = stmt.executeUpdate();

        } catch (SQLException e) {
            throw new RuntimeException("数据表更新失败:" + e.getMessage());
        }
        return row;
    }

    private static List<Method> getAllMethods(Class<?> clazz) {
        if (clazz == null) {
            return new ArrayList<>();
        }
        // 获取当前类声明的所有方法
        List<Method> methods =  new ArrayList<>();
        for(Method method : clazz.getDeclaredMethods())
            if(!methods.contains(method))
                methods.add(method);
        // 获取当前类继承的所有公共方法
        for(Method method : clazz.getMethods())
            if(!methods.contains(method))
                methods.add(method);
        // 递归获取父类的方法
        methods.addAll(getAllMethods(clazz.getSuperclass()));
        return methods;
    }

    /**
     * 根据 结果集，映射成一个java实体对象
     * @param clazz
     * @param rs
     * @return
     * @param <T>
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws SQLException
     * @throws InvocationTargetException
     */
    private static <T> T getObject(Class<T> clazz, ResultSet rs) throws InstantiationException, IllegalAccessException, SQLException, InvocationTargetException {
        T t = clazz.newInstance();
        ResultSetMetaData metaData = rs.getMetaData(); // 获取结果集的元数据对象
        List<Method> methods = getAllMethods(clazz); // 获取实体类及继承中所有方法对象

        for (int i = 1; i <= metaData.getColumnCount(); i++) { // 根据结果集的列的数据循环
            String fieldName = metaData.getColumnLabel(i); // 获取列名
            String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); // 拼接set方法名

            boolean matcher = false;
            for (Method m : methods) {
                Class<?> paramType = null;
                try {
                    if (m.getName().equals(methodName)) {
                        paramType = m.getParameterTypes()[0];
                        Object value = rs.getObject(fieldName); // 从结果集中获取值

                        // 特殊处理 status 字段
                        if ("status".equalsIgnoreCase(fieldName)) {
                            if (paramType == Integer.class || paramType == int.class) {
                                value = rs.getInt(fieldName);
                            } else if (paramType == Long.class || paramType == long.class) {
                                value = rs.getLong(fieldName);
                            } else if (paramType == Boolean.class || paramType == boolean.class) {
                                value = rs.getBoolean(fieldName);
                            } else {
                                throw new IllegalArgumentException("Unsupported type for status field: " + paramType);
                            }
                        } else {
                            // 根据参数类型进行显式转换
                            if (paramType == Integer.class || paramType == int.class) {
                                value = rs.getInt(fieldName);
                            } else if (paramType == Long.class || paramType == long.class) {
                                value = rs.getLong(fieldName);
                            } else if (paramType == Double.class || paramType == double.class) {
                                value = rs.getDouble(fieldName);
                            } else if (paramType == Float.class || paramType == float.class) {
                                value = rs.getFloat(fieldName);
                            } else if (paramType == Boolean.class || paramType == boolean.class) {
                                value = rs.getBoolean(fieldName);
                            } else if (paramType == String.class) {
                                value = rs.getString(fieldName);
                            } else if (paramType == Date.class) {
                                value = rs.getDate(fieldName);
                            } else if (paramType == Timestamp.class) {
                                value = rs.getTimestamp(fieldName);
                            }
                        }

                        m.invoke(t, value); // 执行指定方法
                        matcher = true;
                        break;
                    }
                } catch (Exception e) {
                    throw new RuntimeException("获取[" + fieldName + "]属性时出错,方法的参数类型是:" + paramType + "：" + e.getMessage());
                }
            }
            if (!matcher) {
                throw new RuntimeException("没有获取到【" + fieldName + "】属性值，请检查实体类的字段名和数据表中的列名是否一致。如果不一致可以在select语句中加 as 别名");
            }
        }
        return t;
    }

    public static Connection getConn() {
        if (conn == null) {
            try {
                conn = DriverManager.getConnection(url, username, password);
            } catch (SQLException e) {
                throw new RuntimeException("无法连接到数据库: " + e.getMessage());
            }
        }
        return conn;
    }
}
